#include "BSTMap.h"
#include "FileOperation.h"
#include "AVLTree.h"
#include <iostream>
#include <algorithm>
using namespace std;

template<typename K, typename V>
class HashTable{
private:
	
	int M; // 取模的那个素数，表的长度
	int size; // 表中存储数据的个数
	AVLTree<K, V> *hashTable[];
	
	int hashCode(K key) {
		std::hash<K> key_hash;
		return key_hash(key);
	}
	
public:
	
	HashTable(int M) {
		this->M = M;
		size = 0;
		*hashTable = new AVLTree<K, V>[M];
		for (int i = 0; i < M; ++i) {
			hashTable[i] = new AVLTree<K, V>();
		}
	}
	
	HashTable() {
		this->M = 97;
		size = 0;
		*hashTable = new AVLTree<K, V>[M];
		for (int i = 0; i < M; ++i) {
			hashTable[i] = new AVLTree<K, V>();
		}
	}
	
	int hash(K key){
		return (hashCode(key) & 0x7fffffff) % M;
	}
	
	void add(K key, V value){
		AVLTree<K,V> *bstMap = hashTable[hash(key)];
		if(bstMap->contains(key)){
			bstMap->set(key,value);
		}else{
			bstMap->add(key,value);
			size++;
		}
	}
	
	V remove(K key){
		V value;
		AVLTree<K,V> *bstMap = hashTable[hash(key)];
		if(bstMap->contains(key)){
			value = bstMap->remove(key);
			size--;
			
			return value;
		}else{
			throw "no this key";
		}

	}

	
	int getSize(){
		return size;
	}
	bool contains(K key){
		return hashTable[hash(key)]->contains(key);
	}
	
	V get(K key){
		return hashTable[hash(key)]->get(key);
	}
	
	void set(K key, V value){
		AVLTree<K,V> *bstMap = hashTable[hash(key)];
		if(bstMap->contains(key)){
			bstMap->set(key,value);
		}else{
			bstMap->add(key,value);
			size++;
		}
	}
};

int main(){
	cout << "pride-and-prejudice.txt" << endl;
	string filename = "pride-and-prejudice.txt";
	HashTable<string, int> *hashT = new HashTable<string, int>();
	vector<string> words;
	if (FileOps::readFile(filename, words)) {
		std::sort(words.begin(),words.end());
		cout << "Total words: " << words.size() << endl;
		clock_t startTime = clock();
		for (string word : words) {
			if (hashT->contains(word)) {
				hashT->set(word, hashT->get(word) + 1);
			} else {
				hashT->add(word, 1);
			}
		}
		for(string word: words){
			hashT->contains(word);
		}
		/*
		for(string word: words){
			try{
				hashT->remove(word);
			}catch(exception e){
				continue;
			}
			
		  }*/
		clock_t endTime = clock();
		cout << "HashTable: "<< double(endTime - startTime)/CLOCKS_PER_SEC << "s" <<endl;
		cout << "Total different words: " << hashT->getSize() << endl;
		cout << "Frequency of PRIDE: " << hashT->get("pride") << endl;
		cout << "Frequency of PREJUDICE: " << hashT->get("prejudice") << endl;

	}
	

	return 0;
}
